package bma.common.langutil.ai.common;

import bma.common.langutil.ai.AIUtil;
import bma.common.langutil.ai.stack.AIStack;
import bma.common.langutil.ai.stack.AIStackSimple;

/**
 * 遍及AIIterator的对象
 * 
 * @author guanzhong
 * @since 1.0 (imported from BMA.ESP Project)
 * 
 * @param <RESP_TYPE>
 * @param <ITEM_TYPE>
 */
public abstract class AIIteratorTraverser<ITEM_TYPE, RESP_TYPE> {

	public enum Evaluation {
		CONTINUE, END, ASYNCH
	}

	protected AIStack<RESP_TYPE> stack;
	protected AIIterator<ITEM_TYPE> iterator;

	public AIIteratorTraverser(AIStack<RESP_TYPE> stack,
			AIIterator<ITEM_TYPE> iter) {
		super();
		this.stack = stack;
		this.iterator = iter;
	}

	public boolean execute() {
		return executeOne();
	}

	protected boolean executeOne() {
		try {
			while (true) {
				AIStackSimple<Boolean> hstack = new AIStackSimple<Boolean>(
						stack);
				if (!iterator.hasNext(hstack)) {
					return hstack.callback(new AIResultHandler<Boolean>() {
						@Override
						public void success(Boolean result) {
							if (result) {
								executeOne();
							} else {
								end();
							}
						}
					});
				}
				if (!hstack.get())
					break;
				AIStackSimple<ITEM_TYPE> istack = new AIStackSimple<ITEM_TYPE>(
						stack);
				if (iterator.next(istack)) {
					ITEM_TYPE item = istack.get();
					Evaluation eval = handle(item);
					switch (eval) {
					case ASYNCH:
						return false;
					case CONTINUE:
						continue;
					case END:
						return true;
					}
				} else {
					return istack.callback(new AIResultHandler<ITEM_TYPE>() {
						@Override
						public void success(ITEM_TYPE result) {
							Evaluation eval = handle(result);
							switch (eval) {
							case ASYNCH:
								return;
							case CONTINUE:
								executeOne();
							case END:
								return;
							}
						}
					});
				}
			}
			return end();
		} catch (Exception e) {
			return stack.failure(e);
		}
	}

	protected abstract Evaluation handle(ITEM_TYPE item);

	protected abstract boolean end();

	protected boolean success(RESP_TYPE v) {
		return this.stack.success(v);
	}

	protected boolean failure(Throwable t) {
		return this.stack.failure(t);
	}

	protected <VTYPE> VTYPE get(AIStackSimple<VTYPE> s) {
		try {
			return s.get();
		} catch (Exception e) {
			stack.failure(AIUtil.exception(e));
			return null;
		}
	}
}
